from Crypto.Cipher import AES, DES
from Crypto.Util.Padding import pad, unpad
import binascii
import time
import os
import tkinter as tk
from tkinter import filedialog
import xml.etree.ElementTree as ET

# 作者：知夏秋天
# git地址：https://gitee.com/ZhixiaAutumn/simple-tools.git

# 先去命令行安装：pip install pycryptodome
# 使用Navicat 文件=》导出需要查看密码的连接（勾选导出密码）
# 选择导出的ncx文件，等待返回结果

class NavicatPassword:
    def __init__(self, version=12):
        self.version = version
        self.blowKey = binascii.unhexlify('3DC5CA39')
        self.blowIv = binascii.unhexlify('d9c7c3c8870d64bd')
        self.aesKey = b'libcckeylibcckey'
        self.aesIv = b'libcciv libcciv '

    def encrypt(self, string):
        if self.version == 11:
            return self.encryptEleven(string)
        elif self.version == 12:
            return self.encryptTwelve(string)
        else:
            raise ValueError("Unsupported version")

    def encryptEleven(self, string):
        cipher = DES.new(self.blowKey, DES.MODE_ECB)
        padded_data = pad(string.encode(), 8)
        encrypted = cipher.encrypt(padded_data)
        return binascii.hexlify(encrypted).decode().upper()

    def encryptTwelve(self, string):
        cipher = AES.new(self.aesKey, AES.MODE_CBC, self.aesIv)
        padded_data = pad(string.encode(), AES.block_size)
        encrypted = cipher.encrypt(padded_data)
        return binascii.hexlify(encrypted).decode().upper()

    def decrypt(self, hex_string):
        if self.version == 11:
            return self.decryptEleven(hex_string)
        elif self.version == 12:
            return self.decryptTwelve(hex_string)
        else:
            raise ValueError("Unsupported version")

    def decryptEleven(self, hex_string):
        encrypted_data = binascii.unhexlify(hex_string)
        cipher = DES.new(self.blowKey, DES.MODE_ECB)
        decrypted = unpad(cipher.decrypt(encrypted_data), 8)
        return decrypted.decode()

    def decryptTwelve(self, hex_string):
        encrypted_data = binascii.unhexlify(hex_string)
        cipher = AES.new(self.aesKey, AES.MODE_CBC, self.aesIv)
        decrypted = unpad(cipher.decrypt(encrypted_data), AES.block_size)
        return decrypted.decode()

def parse_ncx_file(file_path):
    tree = ET.parse(file_path)
    root = tree.getroot()
    password = None
    for connection in root.findall('.//Connection'):
        password = connection.get('Password')
        if password:
            break
    return password

# 测试代码
if __name__ == "__main__":
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口
    file_path = filedialog.askopenfilename(title="选择Navicat连接文件", filetypes=[("NCX files", "*.ncx")])
    if not file_path:
        print("未选择文件")
    else:
        password = parse_ncx_file(file_path)
        if password:
            print(f"从文件中提取到的密文: {password}")
            try:
                navicatPasswordV11 = NavicatPassword(11)
                decoded_resultV11 = navicatPasswordV11.decrypt(password)
                print(f"Navicat版本11之前的解密结果: {decoded_resultV11}")
            except Exception as e:
                print(f"Navicat版本11之前的解密失败: {e}")
            try:
                navicatPasswordV12 = NavicatPassword(12)
                decoded_resultV12 = navicatPasswordV12.decrypt(password)
                print(f"Navicat版本12之后的解密结果: {decoded_resultV12}")
            except Exception as e:
                print(f"Navicat版本12之后的解密失败: {e}")
        else:
            print("未能从文件中提取到密码")
    
    # 等待8秒后关闭窗口
    print(f"8秒后自动关闭窗口")
    time.sleep(8)
    os.system("taskkill /f /im python.exe")
